--collection of factories--
local astroidImage = love.graphics.newImage('assets/textures/asteroid2.png')

--Weapons
local laser = love.graphics.newImage('assets/textures/laser1.png')
local laser2 = love.graphics.newImage('assets/textures/laser2.png')
local emp = love.graphics.newImage('assets/textures/Weapons/emp.png')

--Explosion
local exp1 = love.graphics.newImage('assets/textures/explosion1Anim/anim.png')
local exp1Small = love.graphics.newImage('assets/textures/explosion1Anim/anim2.png')

--SoundFX
local laserSound = love.sound.newSoundData('assets/sounds/laser1.ogg')
local engineSound = love.sound.newSoundData('assets/sounds/engine1.ogg')
local expSound1 = love.sound.newSoundData('assets/sounds/explosion1.ogg')
local expSound2 = love.sound.newSoundData('assets/sounds/explosion2.ogg')
local empSound = love.sound.newSoundData('assets/sounds/Weapons/emp.ogg')

--Soundtracks
local soundtrack1 = love.audio.newSource('assets/sounds/ForHire.ogg', 'stream')

--Enemies
local basicEnemy1 = love.graphics.newImage('assets/textures/ship2Anim/anim.png')
local speeder1 = love.graphics.newImage('assets/textures/speeder/anim.png')
local mine = love.graphics.newImage('assets/textures/mines/mine1.png')

--Powerups
local wrench = love.graphics.newImage('assets/textures/PowerUps/wrench.png')

--Categories
-- 1 = asteroids/world objects/ etc
-- 2 = player
-- 3 = player's lasers/emps
-- 4 = Basic Enemy
-- 5 = Basic enemy's lasers
-- 6 = Speeder
-- 7 = mine
-- 8 = PowerUps
-- 9 = EMP

--player
EntitySystem.factory("player", function(x, y, w, h, i, ti, gx, gy, mSpeed, numFrames, animSpeed, animName)
    local af = '1-'..numFrames
    local g = anim8.newGrid(gx,gy, i:getWidth(), i:getHeight())
      return EntitySystem.entity(
              {"shape", {size = Vector.new(gx, gy), form = "rect"}},
              {"position", Vector.new(x, y)},
              {"physics", {bodyType = "dynamic", category = 2}},
              {"audio", {sound = engineSound, loop = true, volume = 0.05}},
              {"reload"},
              {"weapons"},
              {"onDeath", {action = playerDeath}},
              {"inCam"},
              {'health'},
              {"animation", {numFrames = numFrames, image = i, turboImage = ti, width = i:getWidth(), i:getHeight(), name = animName, grid = g, anim = anim8.newAnimation(g(af,1), animSpeed) }},
              {"movement", {speed = mSpeed, turboSpeed = 1.5*mSpeed}},
              {"sector"})
end)

EntitySystem.factory("enemy", function(x, y, w, h, i, gx, gy, mSpeed, numFrames, animSpeed, animName, n, category)
    local af = '1-'..numFrames
    local g = anim8.newGrid(gx,gy, i:getWidth(), i:getHeight())
    
    local d = 5
    if n == 1 then
      d = 10
    elseif n == 2 then
    end
      return EntitySystem.entity(
              {"shape", {size = Vector.new(gx, gy), form = "rect"}},
              {"position", Vector.new(x, y)},
              {"physics", {bodyType = "dynamic", category = category}},
              {"reload", {cat = 5, typ = 2, speed = 1}},
              {"type",   {num = n}},
              {"animation", {numFrames = numFrames, image = i, width = i:getWidth(), i:getHeight(), name = animName, grid = g, anim = anim8.newAnimation(g(af,1), animSpeed) }},
              {"movement", {speed = mSpeed}},
              {"sector"},
               {"onDeath", {action = enemyDeath1}},
              {"damage", {amount = d}},
              {"trackPlayer"})
end)

--Now using this to hold world components, such as the soundtrack
EntitySystem.factory("level", function()
  --create a random level
  local level = EntitySystem.entity(
            {"audio", {source = soundtrack1, volume = 0.5, loop = true, stream = "stream"}},
            {"text"},
            {"rectangle"},
            {"hudImage"})
  return level
end)
    

--BOXES
EntitySystem.factory("box", function(x, y, w, h, r, g, b, a)
  return EntitySystem.entity(
          {"shape", {size = Vector.new(w,  h), form = "rect"}},
          {"position", Vector.new(x, y)},
          {"color", { r = r, g = g, b = b, a = a }})
end)
EntitySystem.factory("boxI", function(x, y, i)
  return EntitySystem.entity(
          {"shape", {size = Vector.new(i:getWidth(),  i:getHeight()), form = "rect"}},
          {"position", Vector.new(x, y)},
          {"texture", {image = i, width = i:getWidth(), i:getHeight()}})
end)

--
--Explosions
--Explosion1
EntitySystem.factory("explosion1", function(x,y,px,py, t)
    local dist = math.dist(px,py,x,y)
    local vol
    if dist < 2000 then
      vol = 0.5
    else
      vol = 0
    end
    
    local g
    local i
    if t == 1 then
      g = anim8.newGrid(140,140, exp1:getWidth(), exp1:getHeight())
      i = exp1
    else
      g = anim8.newGrid(35,35, exp1Small:getWidth(), exp1Small:getHeight())
      i = exp1Small
    end
    return EntitySystem.entity(
      {"position", Vector.new(x, y)},
      {"animation", {numFrames = 6, image = i, width = i:getWidth(), i:getHeight(), grid = g, anim = anim8.newAnimation(g('1-6',1), 0.05) }},
      {"audio", {sound = expSound1, volume = vol}},
      {'duration', {remaining = 0.3}})
end)
--
--Explosion2
EntitySystem.factory("explosion2", function(x,y,px,py, t)
    local dist = math.dist(px,py,x,y)
    local vol
    if dist < 2000 then
      vol = 0.5
    else
      vol = 0
    end
    
    local g
    local i
    if t == 1 then
      g = anim8.newGrid(140,140, exp1:getWidth(), exp1:getHeight())
      i = exp1
    else
      g = anim8.newGrid(35,35, exp1Small:getWidth(), exp1Small:getHeight())
      i = exp1Small
    end
    return EntitySystem.entity(
      {"position", Vector.new(x, y)},
      {"animation", {numFrames = 6, image = i, width = i:getWidth(), i:getHeight(), grid = g, anim = anim8.newAnimation(g('1-6',1), 0.05) }},
      {"audio", {sound = expSound2, volume = vol}},
      {'duration', {remaining = 0.3}})
end)
--
--Weapons
--Laser
 EntitySystem.factory("laser", function(x, y, vx, vy, angle, whichLaser, cat, px,py)
    local vol
    local dist = math.dist(px,py,x,y)
    if dist < 2000 then
      vol = 0.1
    else
      vol = 0
    end

    local i
    if whichLaser == 1 then
      i = laser
    elseif whichLaser == 2 then
      i = laser2
    else
      i = laser
    end
    local c = cat
    
  return EntitySystem.entity(
          {"shape", {size = Vector.new(i:getWidth(),  i:getHeight()), form = "rect"}},
          {"position", Vector.new(x, y)},
          {"duration"},
          {"damage"},
          {"physics", {bodyType = "dynamic", category = c, startXVel = vx, startYVel = vy, startAngle = angle, density = 0.1}},
          {"audio", {sound = laserSound, volume = vol}},
          {"texture", {image = i, width = i:getWidth(), i:getHeight()}})
end)
--EMP
EntitySystem.factory("emp", function(x,y)
  local g = anim8.newGrid(40,40, emp:getWidth(), emp:getHeight())
  
  return EntitySystem.entity(
    {'shape', {size = Vector.new(emp:getHeight(),emp:getHeight()), form = "circ"}},
    {"position", Vector.new(x, y)},
    {"animation", {numFrames = 4, image = emp, width = emp:getWidth()/4, emp:getHeight(), grid = g, anim = anim8.newAnimation(g('1-4',1), 0.1) }},
    {"physics", {bodyType = "dynamic", category = 9, mask = 2, density = 10}},
    {"audio", {sound = empSound, volume = 0.2}},
    {'duration', {remaining = 3}})
end)
--
--
EntitySystem.factory("texCircle", function(x, y, i, randStartVel, isAst, cat, onDeath)
    local sx,sy
    local form
    local c = cat or 1
    local d = 0
    
    if cat == 7 then
      d = 20
    end
    
    local death = onDeath or nil
    
    --Allow asteroids to have a different physics body than a regular circle
    if isAst then
      form = "ast"
    else
      form = "circ"
    end
      
    if randStartVel then
      sx = math.random(-10000,10000)
      sy = math.random(-10000,10000)
    else
      sx = 0
      sy = 0
    end
  return EntitySystem.entity(
          {"shape", {size = Vector.new(i:getWidth(),  i:getHeight()), form = form}},
          {"position", Vector.new(x, y)},
          {"damage",  {amount = d}},
          {"onDeath", {action = death}},
          {"physics", {bodyType = "dynamic", category = c, startXVel = sx, startYVel = sy}},
          {"texture", {image = i, width = i:getWidth(), i:getHeight()}})
end)

--
--
--
--Sector
--SectNum used to increase difficulty as the game goes on
EntitySystem.factory("sector", function(x,y, rand, sectNum)
    local g = {}
    --Spacing for asteroids
    local size = 300
    for i = 1, 6, 1 do
      g[i] = {}
      for j = 1, 4, 1 do
        if rand then
          g[i][j] = math.random(0,1000)
        else
          g[i][j] = 0
        end
        --Separate function to keep things clean
        fillSector(sectNum,g,i,j, size,x,y)
      end
      end
end)
--
--
function fillSector(sectNum,g,i,j, size,x,y)
  --Asteroids
  local astConst = math.clamp(70, 70 + sectNum, 90)
  local basConst = math.clamp(astConst + 1, astConst + sectNum, astConst + 35)
  local speConst = math.clamp(basConst + 1, basConst + 1 + sectNum, basConst + 1 + 15)
  local minConst = math.clamp(speConst + 1, speConst + 1 + sectNum,speConst + 1 + 60)
  local heaConst = minConst + 2
  
  if g[i][j] <= astConst then
    local ast = EntitySystem.entity.texCircle(i*size - x*1920, j*size - y*1080, astroidImage, true, true)
  --Basic Enemy
  elseif g[i][j] <= basConst then
    local en = EntitySystem.entity.enemy(i*size - x*1920, j*size - y*1080,100,100, basicEnemy1, 146, 35, 600, 2, 0.1, "DefaultFlying", 1, 4)
  --Speeder
  elseif g[i][j] <= speConst then
    local en = EntitySystem.entity.enemy(i*size - x*1920, j*size - y*1080,100,100, speeder1, 18, 12, 1000, 2, 0.1, "DefaultFlying", 2, 6)
  --Mine
  elseif g[i][j] <= minConst then
    local mn = EntitySystem.entity.texCircle(i*size - x*1920, j*size - y*1080, mine, false, false, 7, enemyDeath1)
  --HealthUp
  elseif g[i][j] <= heaConst then
    local hu = EntitySystem.entity.healthUp(i*size - x*1920, j*size - y*1080)
  end
end
--
--PowerUps
EntitySystem.factory("healthUp", function(x, y)
  local g = anim8.newGrid(150,150, wrench:getWidth(), wrench:getHeight())
  return EntitySystem.entity(
          {"shape", {size = Vector.new(wrench:getWidth()/6,  wrench:getHeight()), form = "rect"}},
          {"position", Vector.new(x, y)},
          {"onDeath", {action = deleteEnt}},
          {"animation", {numFrames = 6, image = wrench, width = wrench:getWidth()/6, wrench:getHeight(), grid = g, anim = anim8.newAnimation(g('1-6',1), 0.2) }},
          {"powerUp", {colType = "rect", width = (wrench:getWidth()/6) - (wrench:getWidth()/6) / 5, height = wrench:getHeight() - wrench:getHeight()/5, action = healthUpFunction}})
end)